package cn.tannn.cat.file.sdk.core.ftp;

import cn.tannn.cat.file.sdk.bean.FileStorage;
import cn.tannn.cat.file.sdk.config.FtpConfig;
import cn.tannn.cat.file.sdk.core.OssCache;
import cn.tannn.cat.file.sdk.exception.FileException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;
import java.util.Objects;

/**
 * ftp create client
 *
 * @author <a href="https://t.tannn.cn/">tan</a>
 * @date 2024/6/12 下午1:32
 */
@Slf4j
public class FtpUtils {
    /**
     * 创建Ftp client cache
     *
     * @param fileStorageId Ftp{@link FileStorage}
     */
    public static FTPClient createFtpClient(Long fileStorageId) {
        FileStorage fileStorage = OssCache.ftpConnectInfoCache.get(fileStorageId);
        return createFtpClient(fileStorage);
    }

    /**
     * 创建ftp client
     *
     * @param fileStorage ftp{@link FileStorage}
     */
    public static FTPClient createFtpClient(FileStorage fileStorage) {
        FTPClient ftpClient = new FTPClient();
        try {
            FtpConfig ftpConfig = fileStorage.getConfig().toJavaObject(FtpConfig.class);
            if (Objects.nonNull(ftpConfig)) {
                connectAndLogin(ftpClient, ftpConfig);
                //是否成功登录服务器
                int replyCode = ftpClient.getReplyCode();
                if (!FTPReply.isPositiveCompletion(replyCode)) {
                    log.error("===> ftp《{}》connect failed ，ftp服务器: {}:{}", fileStorage.getName()
                            , ftpConfig.getHostname()
                            , ftpConfig.getPort());
                    /**
                     * 如果 FTP 服务器响应错误 中断传输、断开连接
                     * abort：中断文件正在进行的文件传输，成功时返回 true,否则返回 false
                     * disconnect：断开与服务器的连接，并恢复默认参数值
                     */
                    ftpClient.abort();
                    ftpClient.disconnect();
                }
                ftpClient.setControlEncoding("utf-8");
                // 尝试使用OPTS UTF8 ON命令启用UTF-8编码（某些服务器支持）
                ftpClient.sendCommand("OPTS UTF8", "ON");
                // ID 是唯一的
                log.info("===> ftp《{}》connect success", fileStorage.getName());
            }
            return ftpClient;
        } catch (Exception e) {
            log.error("===>  ftp《{}》配置异常，请检查", fileStorage.getName(), e);
            throw FileException.specialMessage("===>  ftp《{}》配置异常，请检查", e);
        }
    }


    /**
     * 关闭FTP服务链接
     */
    public static void disConnection(FTPClient ftpClient) {
        try {
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
        } catch (IOException e) {
            log.error("ftp client coles err", e);
        }
    }


    /**
     * 删除 ftp client cache
     *
     * @param fileStorageId 存储器ID
     */
    public static void deleteFtpConnectInfo(Long fileStorageId) {
        try {
            OssCache.ftpConnectInfoCache.remove(fileStorageId);
        } catch (Exception e) {
            log.error("删除ftp connect info cache 失败 fileStorageId {}", fileStorageId, e);
        }
    }

    /**
     * 创建多级目录
     * @param ftp FTPClient
     * @param dirPath 多级目录
     * @throws IOException IOException
     */
    public static void createMultiLevelDirectory(FTPClient ftp, String dirPath) throws IOException {
        String[] dirs = dirPath.split("/");
        String currentPath = "";
        for (String dir : dirs) {
            if (dir == null || dir.trim().isEmpty()) {
                continue;
            }
            currentPath += "/" + dir;
            if (!directoryExists(ftp, currentPath)) {
                boolean created = ftp.makeDirectory(currentPath);
                if (created) {
                    log.info("Directory created successfully: {}", currentPath);
                } else {
                    log.info("Failed to create directory: {}", currentPath);
                }
            }
        }
    }


    /**
     * 检查目录是否存在
     *
     * @param ftp     FTPClient
     * @param dirPath 目录路径
     * @return true存在
     * @throws IOException IOException
     */
    public static boolean directoryExists(FTPClient ftp, String dirPath) throws IOException {
        ftp.changeWorkingDirectory(dirPath);
        int returnCode = ftp.getReplyCode();
        return returnCode == 250;
    }


    /**
     * 检查连接是否仍然有效，必要时重新连接
     *
     * @param ftp       FTPClient
     * @param ftpConfig FtpConfig
     * @throws IOException IOException
     */
    public static void checkAndReconnect(FTPClient ftp, FtpConfig ftpConfig) throws IOException {
        if (!ftp.isConnected() || !ftp.sendNoOp()) {
            connectAndLogin(ftp, ftpConfig);
        }
    }


    /**
     * 连接并登录FTP服务器
     *
     * @param ftpClient FTPClient
     * @param ftpConfig FtpConfig
     * @throws IOException IOException
     */
    public static void connectAndLogin(FTPClient ftpClient, FtpConfig ftpConfig) throws IOException {
        //连接ftp服务器
        ftpClient.connect(ftpConfig.getHostname(), ftpConfig.getPort());
        //登录ftp服务器
        if (StringUtils.isNotBlank(ftpConfig.getUsername()) && StringUtils.isNotBlank(ftpConfig.getPassword())) {
            ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
        } else {
            // 使用匿名登录
            // https://blog.csdn.net/wangmx1993328/article/details/82150290
            ftpClient.login("Anonymous", "");
        }
    }
}
